package com.wxxymaker.utils;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import com.blade.kit.Base64;
import com.blade.kit.UUID;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class QRCodeUtil {
	private static Logger log = LoggerFactory.getLogger("QRCodeUtil");
	private static Map<EncodeHintType, String> encodeMap = new HashMap<>();

	private static HttpServletRequest request;
	static {
		String CHARSET = "utf-8";
		encodeMap.put(EncodeHintType.CHARACTER_SET, CHARSET);
	}

	/**
	 * 获取二维码信息
	 *
	 * 6.7 limit信息变成固定的，即不会刷新连接
	 * @param request HttpServletRequest
	 * @param stageId 阶段id
	 * @param targetShop 二维码指定的被打分公司，可以实现每张二维码不同打分公司 6.14
	 *                   直接将加密的id列表放在url中，在markView进行解密 获取
	 *                   如果该值为null或空 都不做限制 为该阶段下的全部
	 */
	public static QRCode flush(HttpServletRequest request, Integer stageId, Integer[] targetShop) {
		QRCodeUtil.request = request;

		if (stageId == null || stageId <= 0) {
			throw new RuntimeException("StageId 不能为空！");
		}
		String        filename = UUID.captchaChar(10) + ".png";
		File          img      = FileUtil.createFile(request.getServletContext().getRealPath("WEB-INF/static/qrcode/"), filename);
		String        limit    = Base64.encodeToString(("wxxymaker_" + stageId).getBytes(), Base64.NO_WRAP);
		StringBuffer  url      = request.getRequestURL();
		String        context  = url.substring(0, url.indexOf("/", 8));
		StringBuilder code     = new StringBuilder(context + "/user/markView/" + stageId + "?limit=" + limit);
		// 有指定的公司id添加到url中
		if (targetShop != null && targetShop.length > 0) {
			String hexIds = ArrayUtils.toHexString(targetShop);
			code.append("&ids=").append(hexIds);
		}
		try {
			QRCodeUtil.encode(code.toString(), new FileOutputStream(img));
		} catch (FileNotFoundException e) {
			log.error("文件不存在！ --> {}", e.getMessage());
		}
		QRCode qrCode = new QRCode(context + "/static/qrcode/" + filename, code.toString(),
				context + "/download/qrcode/" + filename);
		SimpleCache.set(Const.QRLIMIT, limit);
		SimpleCache.set(Const.QRCODEINFO, qrCode);
		return qrCode;
	}

	/**
	 * 预先从缓存中获取二维码信息，获取不到则重新生成
	 * @param request HttpServletRequest
	 * @param stageId 阶段id
	 */
	public static QRCode get(HttpServletRequest request, Integer stageId, Integer[] targetShop) {
		QRCode qrCode = (QRCode) SimpleCache.get(Const.QRCODEINFO);
		if (null == qrCode || null == qrCode.getUrl()) {
			return flush(request, stageId, targetShop);
		}
		return qrCode;
	}

	/**
	 * 清除QR信息缓存
	 */
	public static void clear() {
		SimpleCache.remove(Const.QRCODEINFO);
		SimpleCache.remove(Const.QRLIMIT);
	}

	/**
	 * 生成450x450的二维码
	 * @param string  加密字符串
	 * @param output  输出流
	 */
	private static void encode(String string, OutputStream output) {
		Integer SIZE = 450;
		QRCodeUtil.encode(string, SIZE, output);
	}

	/**
	 * 生成指定尺寸的二维码
	 * @param string 加密字符串
	 * @param size   尺寸
	 * @param output 二维码输出流
	 */
	private static void encode(String string, Integer size, OutputStream output) {
		try {
			BitMatrix bitMatrix = new QRCodeWriter().encode(string, BarcodeFormat.QR_CODE,
					size, size, encodeMap);  // 根据要加密的内容生成QR矩阵
			int width  = bitMatrix.getWidth();
			int height = bitMatrix.getHeight();
			BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			for (int w = 0; w < width; w++) {  // 将矩阵写入图片
				for (int h = 0; h < height; h++) {
					image.setRGB(w, h, bitMatrix.get(w, h) ? 0xFF000000 : 0xFFFFFFFF);
				}
			}

			Graphics2D g = image.createGraphics();  // 获取画笔
			BufferedImage logo = ImageIO.read(new FileInputStream(getLogo()));
			// logo大小
			int lw = (int) (image.getWidth() * 1.2 / 10);
			int lh = (int) (image.getHeight() * 1.2 / 10);
			// 中心
			int x = (image.getWidth() - lw) / 2;
			int y = (image.getHeight() - lh) / 2;

			g.drawImage(logo, x, y, lw, lh, null);
			// logo边框大小
			g.setStroke(new BasicStroke(1));
            // logo边框颜色  
            g.setColor(Color.WHITE);
            g.drawRect(x, y, lw, lh);
            g.dispose();
            logo.flush();
            image.flush();
 			ImageIO.write(image, "png", output);
		} catch (WriterException e) {
			log.error("二维码矩阵生成失败！");
			e.printStackTrace();
		} catch (IOException e) {
			log.error("文件写出失败！");
			e.printStackTrace();
		} finally {
			try {
				output.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获取logo文件
	 */
	private static File getLogo() {
		String path = QRCodeUtil.request.getServletContext().getRealPath("WEB-INF/static/images/logo.png");
		File file = null;
		try {
			file = new File(path);
			if (!file.exists()) {
				return null;
			}
		} catch (Exception e) {
			log.error("获取图片logo失败！" + e);
		}
		return file;
	}

	/**
	 *  QRCode 返回封装类
	 */
	public static class QRCode {
		private String url;
		private String code;
		private String download;

		public QRCode(String url, String code, String download) {
			this.url = url;
			this.code = code;
			this.download = download;
		}

		public String getUrl() {
			return url;
		}

		public void setUrl(String url) {
			this.url = url;
		}

		public String getCode() {
			return code;
		}

		public void setCode(String code) {
			this.code = code;
		}

		public String getDownload() {
			return download;
		}

		public void setDownload(String download) {
			this.download = download;
		}
	}
}